<?php

defined('BASEPATH') or die('forbidden');

/**
 * 分词类
 * @author 穆红伟 QQ:251171960
 * @copyright DirCMS
 * @version Beta 1.0
 * @name split.php
 * @final 2010-8-11 13:33:05
 */
class Split {

    public $dictloadtime;     // 词典载入时间
    public $splitwordstime;    // 分词时间
    public $dictfile = '';     // 字典文件
    private $starttime;       // 分词开始时间
    private $splitchar = ' ';    // 切割符，默认为空格
    private $wordsdict = array();  // 词库（为键值为词，值为词频的数组） 本分次尚未用到词频
    private $cnnumber = '';     // 中文全角字母，数字
    private $punctuation = array(); // 标点符号
    private $trimchars = array();  // 去除的特殊字符
    private $resultstr = array();  // 结果数据

    function __construct() {
        
    }

    /**
     * 加载词库
     */
    function load_dict() {
        $this->starttime = $this->get_microtime();
        $this->dictfile = BASEPATH . 'commons/' . 'dictionary.txt';
        $this->cnnumber = '０|１|２|３|４|５|６|７|８|９|＋|－|％|．|ａ|ｂ|ｃ|ｄ|ｅ|ｆ|ｇ|ｈ|ｉ|ｊ|ｋ|ｌ|ｍ|ｎ|ｏ|ｐ|ｑ|ｒ|ｓ|ｔ|ｕ|ｖ|ｗ|ｘ|ｙ|ｚ|Ａ|Ｂ|Ｃ|Ｄ|Ｅ|Ｆ|Ｇ|Ｈ|Ｉ|Ｊ|Ｋ|Ｌ|Ｍ|Ｎ|Ｏ|Ｐ|Ｑ|Ｒ|Ｓ|Ｔ|Ｕ|Ｖ|Ｗ|Ｘ|Ｙ|Ｚ';
        $this->punctuation = array('\r', '\n', '\t', '`', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '+', '=', '|', '\\', '\'', '"', ';', ':', '/', '?', '.', '>', ',', '<', '[', '{', ']', '}', '·', '～', '！', '＠', '＃', '￥', '％', '……', '＆', '×', '（', '）', '－', '——', '＝', '＋', '＼', '｜', '【', '｛', '】', '｝', '‘', '“', '”', '；', '：', '、', '？', '。', '》', '，', '《', ' ', '　');
        $this->trimchars = array("▲", "△", "▼", "▽", "★", "☆", "◆", "◇", "■", "□", "●", "○", "⊙", "㊣", "◎", "▂", "▁", "▃", "▄", "▅", "▆", "▇", "█", "▏", "▎", "▍", "▌", "▋", "▊", "◢", "◣", "◥", "◤", "▲", "▼", "♀", "♂", "卍", "※");
        $contents = file_get_contents($this->dictfile);
        if ($contents) {
            $wordsdict = explode("\r\n", $contents);
            $i = 0;
            $ttwords = array();
            foreach ($wordsdict as $value) {
                list($twords[], $tfreq[]) = explode("\t", $value);
                $ttwords[$twords[$i]] = $tfreq[$i];
                $i++;
            }
            $this->wordsdict = $ttwords;
        } else {
            throw new Exception('无法载入词典');
        }
        unset($ttwords, $twords, $tfreq, $wordsdict);
        $this->dictloadtime = round($this->get_microtime() - $this->starttime, 7);
    }

    /**
     * 执行分词
     * @param string $str 分词的数据
     * @return array
     */
    function do_split($str) {
        $result = array();
        $spiltchar = $this->splitchar;
        $str = $this->to_half_width($str);
        $strlen = strlen($str); // 需分词的字串长度
        $tmpstr = ''; // 最终结果
        $prechar = 1; // 上一个字符 1：中文 2：英文
        for ($i = 0; $i < $strlen;) {
            if (ord($str[$i]) >= 0x81) {// 中文
                $tchar = $str[$i] . $str[$i + 1] . (isset($str[$i + 2]) ? $str[$i + 2] : '');
                if (in_array($tchar, $this->trimchars) || in_array($tchar, $this->punctuation)) {
                    $tmpstr .= $spiltchar;
                    $i = $i + 3;
                    continue;
                } else {
                    $tmpstr .= ( $prechar == 1) ? $tchar : $spiltchar . $tchar;
                }
                $prechar = 1;
                $i = $i + 3;
            } else {//英文
                // 将不常见字符替换成分隔符
                if (ord($str[$i]) < 32 || in_array($str[$i], $this->punctuation)) {
                    $tmpstr .= $spiltchar;
                    $i++;
                    continue;
                }
                $tmpstr .= ( $prechar == 1) ? $spiltchar . $str[$i] : $str[$i];
                $prechar = 2;
                $i++;
            }
        }
        $tmpstr = array_unique(explode(' ', $tmpstr));
        foreach ($tmpstr as $value) {
            $value = trim($value);
            if ($value) {
                if ((preg_match('/^[0-9a-z]+$/i', $value) && (!preg_match('/^[0-9]+$/i', $value))) || $this->is_words($value)) {
                    $result[] = $value;
                } else {
                    $vstrlen = strlen($value);
                    $vtstr = '';
                    for ($j = $vstrlen; $j >= 2;) {
                        for ($m = 0; $m < $j; $m += 3) {
                            $tlen = $j - $m;
                            $vtstr = substr($value, $m, $tlen);
                            if ($this->is_words($vtstr)) {
                                $result[] = $vtstr;
                                break;
                            }
                        }
                        $j -= strlen($vtstr);
                    }
                }
            }
        }
        $this->resultstr = array_unique(array_reverse($result)); // 重新排序 ；去除重复
        $this->splitwordstime = round($this->get_microtime() - $this->starttime, 7); // 分词时间
        return $this->resultstr;
    }

    /**
     * 判断是否为一个词语
     * @param string $words 判断的数据
     * @return bool
     */
    function is_words($words) {
        if (!trim($words))
            return false;
        return array_key_exists($words, $this->wordsdict);
    }

    /**
     * 获取当前时间的微秒
     * @return int
     */
    function get_microtime() {
        return array_sum(explode(' ', microtime()));
    }

    /**
     * 全角字符切换成半角字符
     * @param string $str 转换的数据
     * @return string
     */
    function to_half_width($str) {
        $cnnumber = explode('|', $this->cnnumber);
        $ennumber = explode('|', '0|1|2|3|4|5|6|7|8|9|+|-|%|.|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z');
        return str_replace($cnnumber, $ennumber, $str);
    }

    function __destruct() {
        unset($this->wordsdict);
    }

}